﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace TripleCComiC
{
    class HighResTimer : UserControl
    {
        private BackgroundWorker _workerTimer;
        private int _interval;
        private int _tickCount;
        //private DateTime _perTime;
        private bool _isWork;
        /// <summary>
        /// Gets or sets the interval at which to raise the Tick event.
        /// </summary>
        [Category("Timer"), Description("Gets or sets the interval at which to raise the Tick event.")]
        public int Interval
        {
            get
            {
                return _interval;
            }
            set
            {
                if (value < 1)
                {
                    _interval = 1;
                }
                else
                {
                    _interval = value;
                }
            }
        }
        /// <summary>
        /// Gets the number of ticks elapsed since the timer started.
        /// </summary>
        [Category("Timer"), Description("Gets the number of ticks elapsed since the timer started.")]
        public int TickCount
        {
            get
            {
                return TickCount;
            }
        }
        /// <summary>
        /// Gets a value indicating whether the timer is running an asynchronous operation.
        [Category("Timer"), Description("Gets a value indicating whether the timer is running an asynchronous operation.")]
        /// </summary>
        public bool IsWork
        {
            get
            {
                return _isWork;
            }
        }

        public HighResTimer()
        {
            _interval = 1000;
            _tickCount = 0;
            _isWork = false;

            _workerTimer = new BackgroundWorker();
            
            _workerTimer.WorkerSupportsCancellation = true;
            _workerTimer.WorkerReportsProgress = true;
            
            _workerTimer.DoWork += _workerTimer_DoWork;
            _workerTimer.ProgressChanged += _workerTimer_ProgressChanged;
        }

        /// <summary>
        /// Starts execution of a background operation.
        /// </summary>
        public void Start()
        {
            if (!(_isWork || _workerTimer.IsBusy))
            {
                _isWork = true;
                _tickCount = 0;
                //_perTime = DateTime.Now;
                _workerTimer.RunWorkerAsync();
            }
        }

        /// <summary>
        /// Requests cancellation of a pending background operation.
        /// </summary>
        public void Stop()
        {
            if (_isWork)
            {
                _workerTimer.CancelAsync();
                _tickCount = 0;
                _isWork = false;
            }
        }

        private void _workerTimer_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            EventHandler handler = Tick;
            if (_tickCount > 0)
            {
                _tickCount--;
                if (handler != null)
                {
                    //DateTime now = DateTime.Now;
                    handler(sender, e);
                    //System.IO.File.AppendAllText("record.txt", (now - _perTime).Milliseconds.ToString() + "\n");
                    //_perTime = now;
                }
            }
        }

        private void _workerTimer_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                if (_workerTimer.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }

                _tickCount++;
                _workerTimer.ReportProgress(_tickCount);

                SafeNativeMethods.timeBeginPeriod(1);
                Thread.Sleep(Interval);
                SafeNativeMethods.timeEndPeriod(1);
            }
        }

        /// <summary>
        /// Occurs when the interval elapses.
        /// </summary>
        public event EventHandler Tick;
    }

    internal static class SafeNativeMethods
    {
        [DllImport("winmm.dll")]
        internal static extern uint timeBeginPeriod(uint period);

        [DllImport("winmm.dll")]
        internal static extern uint timeEndPeriod(uint period);
    }
}
